package org.ytor.core.aspect;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.ytor.common.anno.NoWrap;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Ios;
import org.ytor.common.util.excel.Excels;
import org.ytor.core.DownloadMapper;
import org.ytor.core.util.RespUtil;

import java.io.*;
import java.lang.reflect.Method;
import java.util.List;

/**
 * created by yangtong on 2025/5/30 21:33:54
 * <br/>
 * 对DownloadMapper进行增强
 */
@Aspect
@Component
public class DownloadMapperAspect {

    private static final List<Class<?>> SUPPORTED = List.of(List.class, InputStream.class, File.class);

    @Around("@annotation(downloadMapper)")
    public Object handleDownload(ProceedingJoinPoint joinPoint, DownloadMapper downloadMapper) throws Throwable {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        // 判定是否增强，只增强DownloadMapper注解标准的方法
        if (method == null || !method.isAnnotationPresent(DownloadMapper.class)) {
            // 原样处理
            return joinPoint.proceed();
        }

        Class<?> returnType = method.getReturnType();
        Object result = joinPoint.proceed(); // 获取控制器方法的返回值

        // 是否满足增强条件
        boolean shouldHandle = false;
        if (returnType.isArray() && returnType.getComponentType().equals(byte.class)) {
            shouldHandle = true;
        } else if (SUPPORTED.stream().anyMatch(c -> c.isAssignableFrom(returnType))) {
            shouldHandle = true;
        }

        if (!shouldHandle) {
            return result; // 非支持类型，交给 Spring 自己处理
        }

        // 进入增强逻辑
        HttpServletResponse response = RespUtil.getResp();
        RespUtil.downloadResponse(downloadMapper.filename(), downloadMapper.mime());

        try (ServletOutputStream out = response.getOutputStream()) {
            if (result instanceof byte[] bytesResult) {
                //如果接口返回数据是字节，则直接将字节写入响应流
                out.write(bytesResult);
            } else if (result instanceof List listResult) {
                //如果接口返回数据是List，将List转为Excel文件流，再响应
                Excels.write(downloadMapper.type(), listResult, out);
            } else if (result instanceof InputStream isResult) {
                //如果接口返回数据是流，直接写入
                Ios.copyAndClose(isResult, out);
            } else if (result instanceof File fileResult) {
                //如果接口返回数据是File对象，则将File转为流，再写入
                if (!fileResult.exists()) {
                    throw new BaseException("接口返回的文件不存在");
                }
                //获取文件长度
                response.setContentLengthLong(fileResult.length());
                //将文件写入响应
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileResult));
                Ios.copyAndClose(bis, out);
            } else {
                throw new IllegalArgumentException("不支持的返回类型：" + result.getClass());
            }
            out.flush();
        }

        // 阻止 Spring 再处理响应
        return null;
    }

}
